package com.allen.app.common.config.dingtalk;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.allen.app.common.config.other.BusinessException;
import com.allen.app.common.config.aspect.AsyncRequest;
import com.allen.app.common.utils.CheckObjectUtils;
import com.allen.app.common.utils.ServletContextUtil;
import com.allen.app.common.utils.SpringObjPool;
import com.allen.app.common.utils.Try;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

/**
 * @Classname DingTalkHelper
 * @Description 钉钉消息推送工具
 * @Date 2021/09/09 17:28
 * @Created by Limiaojun
 */
@Slf4j
public class DingTalkHelper {

    /**
     * 钉钉配置
     */
    private DingTalkProperties dingTalkProperties;

    /**
     * 初始化方法
     */
    private void ini() {
        dingTalkProperties = Try.tryCatch(() -> SpringUtil.getBean(DingTalkProperties.class), null);
        if (Objects.isNull(dingTalkProperties)) {
            dingTalkProperties = new DingTalkProperties();
        }
    }

    /**
     * 枚举单例
     */
    private enum SingletonEnum {
        INSTANCE;
        private DingTalkHelper dingTalkHelper;

        //私有化枚举的构造函数
        private SingletonEnum() {
            dingTalkHelper = new DingTalkHelper();
            dingTalkHelper.ini();
        }

        public DingTalkHelper getInstnce() {
            return dingTalkHelper;
        }
    }

    /**
     * 默认单例模式
     */
    public static DingTalkHelper getInstance() {
        return SingletonEnum.INSTANCE.getInstnce();
    }

    public static DingTalkHelper getInstance(String dingTalkWebhook) {
        DingTalkHelper dingTalkHelper = new DingTalkHelper();
        dingTalkHelper.ini();
        dingTalkHelper.dingTalkProperties.setDingTalkWebhook(dingTalkWebhook);
        return dingTalkHelper;
    }

    /**
     * 静态方法发送异常钉钉信息
     *
     * @param exception
     */
    public static void send(BusinessException exception) {
        getInstance().sendExceptionMsg(exception);
    }

    /**
     * 发送异常对象钉钉信息.
     *
     * @param exception exception
     * @return void
     * @author Limiaojun
     * @date 2021/09/10 09:13
     */
    public void sendExceptionMsg(BusinessException exception) {
        if(Objects.isNull(exception)){
            return;
        }
        if (exception.isPrintLog()) {
            log.error("BusinessException exception", exception);
        }
        if (!exception.isSendDingTalk()) {
            log.warn("钉钉发送开关未开启");
            return;
        }
        if(!validDingTalkMsg(exception)){
            return;
        }
        HttpServletRequest request = ServletContextUtil.getRequest();
        StringBuilder stb = new StringBuilder();
        stb.append("## 监控报警通知 ").append(MDC.get("logId")) .append("\n\n")
            .append("> 异常时间:\t").append(DateUtil.date().toString()).append("\n\n")
        ;
        if (CheckObjectUtils.nonNull(request)) {
            String env = StrUtil.nullToDefault(SpringUtil.getProperty("spring.profiles.active"), "dev");
            stb.append("> 环境:\t").append(env).append("\n\n")
                .append("> 请求方式:\t").append(request.getMethod()).append("\n\n")
                .append("> 请求地址:\t").append(request.getRequestURI()).append("\n\n")
                .append("> ip地址:\t").append(ServletContextUtil.getIpAddress()).append("\n\n");
        }
        stb.append("> 异常信息:\t").append(exception.toString());
        markdown("监控报警通知", stb.toString(), null, false);
    }

    /**
     * This is a 验证钉钉消息检测是否触发熔断.
     * @param obj 内容
     * @return boolean
     * @author Limiaojun
     * @date 2019/12/28 10:38
     */
    private boolean validDingTalkMsg(Object obj) {
        String key = "dingTalkRate:" + obj.toString().hashCode();
        //如果有redis开启器限流校验
        if (CheckObjectUtils.nonNull(SpringObjPool.getValueOperations())) {
            Boolean flag = SpringObjPool.getValueOperations()
                .setIfAbsent(key, "", dingTalkProperties.getRateLimitSeconds(),
                    TimeUnit.SECONDS);
            Long expire = SpringObjPool.getValueOperations().getOperations().getExpire(key);
            if (Objects.equals(flag,false)) {
                log.warn("同一请求重复发送钉钉,触发自我保护。{}秒后恢复。。。", expire);
                return false;
            }
        }
        return true;
    }

    /**
     * 底层钉钉消息发送方法.
     *
     * @param textMsg textMsg
     * @return void
     * @author Limiaojun
     * @date 2021/09/10 09:15
     */
    @AsyncRequest
    private void send(String textMsg) {
        String post = null;
        try {
            String dingTalkWebhook = dingTalkProperties.getDingTalkWebhook();
            post = HttpUtil.post(dingTalkWebhook, textMsg);
        } catch (Exception e) {
            DingTalkHelper.send(new BusinessException(e).isPrintLog(false));
            log.error("钉钉消息发送失败", e);
        }
        if (Objects.nonNull(post)) {
            log.info("=====================钉钉机器人发送消息:\t{}", post);
        }
    }

    //发送text格式的消息
    public void text(String msg, String[] atMobile, boolean isAtAll) {
        JSONObject object = new JSONObject();
        JSONObject objectText = new JSONObject();
        JSONObject objectAt = new JSONObject();

        objectText.put("content", msg);
        objectAt.put("atMobiles", atMobile);
        objectAt.put("isAtAll", isAtAll);

        object.put("msgtype", "text");
        object.put("text", objectText);
        object.put("at", objectAt);

        send(object.toString());
    }

    //发送link格式的消息
    public void link(String title, String text, String messageUrl, String picUrl) {
        JSONObject object = new JSONObject();
        JSONObject objectLink = new JSONObject();

        objectLink.put("text", text);
        objectLink.put("title", title);
        objectLink.put("picUrl", picUrl);
        objectLink.put("messageUrl", messageUrl);
        object.put("msgtype", "link");
        object.put("link", objectLink);

        send(object.toString());
    }

    //发送markdown格式的消息
    public void markdown(String title, String text, String atMobile, boolean isAtAll) {
        JSONObject object = new JSONObject();
        JSONObject objectMarkdown = new JSONObject();
        JSONObject objectAt = new JSONObject();

        objectMarkdown.put("title", title);
        objectMarkdown.put("text", text);
        objectAt.put("atMobiles", atMobile);
        objectAt.put("isAtAll", isAtAll);

        object.put("msgtype", "markdown");
        object.put("markdown", objectMarkdown);
        object.put("at", objectAt);

        send(object.toString());
    }

    //整体跳转ActionCard类型
    public void actionCard(String title, String text, String singleTitle, String singleURL, int btnOrientation) {
        JSONObject object = new JSONObject();
        JSONObject objectActionCard = new JSONObject();

        objectActionCard.put("title", title);
        objectActionCard.put("text", text);
        objectActionCard.put("btnOrientation", btnOrientation);
        objectActionCard.put("singleTitle", singleTitle);
        objectActionCard.put("singleURL", singleURL);

        object.put("actionCard", objectActionCard);
        object.put("msgtype", "actionCard");

        send(object.toString());
    }

    //独立跳转ActionCard类型
    public void actionCard1(String title, String text, String btnsTitle1, String btnsTitle2, String actionURL1,
        String actionURL2, int btnOrientation) {
        JSONObject object = new JSONObject();
        JSONObject objectActionCard1 = new JSONObject();
        JSONObject objectBtns1 = new JSONObject();
        JSONObject objectBtns2 = new JSONObject();

        objectBtns1.put("title", btnsTitle1);
        objectBtns1.put("actionURL", actionURL1);
        objectBtns2.put("title", btnsTitle2);
        objectBtns2.put("actionURL", actionURL2);

        objectActionCard1.put("title", title);
        objectActionCard1.put("text", text);
        objectActionCard1.put("btnOrientation", btnOrientation);

        JSONArray btns = new JSONArray();
        btns.add(objectBtns1);
        btns.add(objectBtns2);
        objectActionCard1.put("btns", btns);

        object.put("actionCard", objectActionCard1);
        object.put("msgtype", "actionCard");

        send(object.toString());
    }

    //FeedCard类型
    public void feedCard(String title1, String messageURL1, String picURL1, String title2, String messageURL2,
        String picURL2) {
        JSONObject object = new JSONObject();
        JSONObject objectFeedCard = new JSONObject();
        JSONObject objectLink1 = new JSONObject();
        JSONObject objectLink2 = new JSONObject();

        objectLink1.put("title", title1);
        objectLink1.put("messageURL", messageURL1);
        objectLink1.put("picURL", picURL1);

        objectLink2.put("title", title2);
        objectLink2.put("messageURL", messageURL2);
        objectLink2.put("picURL", picURL2);

        JSONArray links = new JSONArray();
        links.add(objectLink1);
        links.add(objectLink2);
        objectFeedCard.put("links", links);

        object.put("feedCard", objectFeedCard);
        object.put("msgtype", "feedCard");

        send(object.toString());
    }
}